package com.uxsino.commons.lic;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.uxsino.commons.model.BaseNeClass;
import com.uxsino.commons.model.NeClass;
import com.uxsino.commons.utils.TimeUtils;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;

@Data
public class AppProperty implements Serializable {
    private static final Logger LOG = LoggerFactory.getLogger(AppProperty.class);

    private String state = "unregistered";// 用于标注系统状态

    private Boolean clean = false;// 用于消息通知清空证书

    /** 序列化版本号 */
    private static final long serialVersionUID = 6624172787844902044L;

    /** 是否是测试版 */
    private Boolean isTest;

    private Date createDate;

    /** 注册时间 */
    private Date installDate;

    /** 开始时间 */
    private Date startDate;

    /** 结束时间 */
    private Date endDate;

    /** 使用的天数 */
    private Integer dateNum;

    private ArrayList<String> moduleIds;

    /** 授权公司名称 */
    private String companyName;

    /** 生成的机器码 **/
    private String key;

    /**
     * 网元数量限制
     **/
    private int limit_network = 0;

    private int limit_server = 0;

    private int limit_database = 0;

    private int limit_storage = 0;

    private int limit_middleware = 0;

    private int limit_other = 0;

    private int limit_app = 0;

    private int limit_virtualization_host = 0;

    private int limit_virtualization_vm = 0;

    private int limit_rac = 0;

    private int limit_cloud = 0;

    private int limit_backup = 0;

    /**
     * 视频监控点数控制
     */
    private int limit_video = 0;

    /**
     * 采集器限制
     */
    private int collector_num = 1;

    public static AppProperty empty() {
        AppProperty p = new AppProperty();
        p.setClean(true);
        return p;
    }

    public boolean validation(String code) {
        if (Strings.isNullOrEmpty(this.getKey()) || Strings.isNullOrEmpty(code) || !code.equals(this.getKey())) {
            LOG.error("[simo license] system code not match !");
            return false;
        }
        return true;
    }

    /** 授权模块ID */
    public boolean validation() {
        Date now = TimeUtils.stringToDate(TimeUtils.formatShortTime(new Date()), "yyyy-MM-dd");
        Date startDateNoHMS = TimeUtils.stringToDate(TimeUtils.formatShortTime(startDate), "yyyy-MM-dd");
        Date endDateNoHMS = TimeUtils.stringToDate(TimeUtils.formatShortTime(endDate), "yyyy-MM-dd");
        if (now.before(startDateNoHMS) || now.after(endDateNoHMS)) {
            return false;
        }

        return true;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        AppProperty other = (AppProperty) obj;
        if (companyName == null) {
            if (other.companyName != null) {
                return false;
            }
        } else if (!companyName.equals(other.companyName)) {
            return false;
        }
        if (createDate == null) {
            if (other.createDate != null) {
                return false;
            }
        } else if (!createDate.equals(other.createDate)) {
            return false;
        }
        if (dateNum == null) {
            if (other.dateNum != null) {
                return false;
            }
        } else if (!dateNum.equals(other.dateNum)) {
            return false;
        }
        if (endDate == null) {
            if (other.endDate != null) {
                return false;
            }
        } else if (!endDate.equals(other.endDate)) {
            return false;
        }
        if (installDate == null) {
            if (other.installDate != null) {
                return false;
            }
        } else if (!installDate.equals(other.installDate)) {
            return false;
        }
        if (isTest == null) {
            if (other.isTest != null) {
                return false;
            }
        } else if (!isTest.equals(other.isTest)) {
            return false;
        }
        if (key == null) {
            if (other.key != null) {
                return false;
            }
        } else if (!key.equals(other.key)) {
            return false;
        }
        if (moduleIds == null) {
            if (other.moduleIds != null) {
                return false;
            }
        } else if (!moduleIds.equals(other.moduleIds)) {
            return false;
        }
        if (startDate == null) {
            if (other.startDate != null) {
                return false;
            }
        } else if (!startDate.equals(other.startDate)) {
            return false;
        }

        return other.limit_network == this.limit_network && other.limit_server == this.limit_server
                && other.limit_database == this.limit_database && other.limit_storage == this.limit_storage
                && other.limit_middleware == this.limit_middleware && other.limit_other == this.limit_other
                && other.limit_app == this.limit_app
                && other.limit_virtualization_host == this.limit_virtualization_host
                && other.limit_virtualization_vm == this.limit_virtualization_vm
                && other.collector_num == this.collector_num;
    }

    /**
     * 验证模块是否拥有权限
     * @param busName： 业务模块名称
     * @return
     */
    public boolean permission(String busName) {
        if (this.moduleIds == null) {
            return Boolean.FALSE;
        } else {
            return this.moduleIds.contains(busName);
        }
    }

    /**
     * 判断当前类型是否能继续入库，剩余点数是否足够
     * @param neCountJson： 统计每一个资源类型已经使用的点数。
     * @param neClass
     * @return  返回剩余可用点数
     */
    public int remained(String neCountJson, NeClass neClass) {
        // 已经使用的资源类型的数量
        Map<NeClass, Integer> ct = Maps.newHashMap();
        if (neClass == null) {
            return 0;
        }

        try {
            if (!Strings.isNullOrEmpty(neCountJson)) {
                ct = JSON.parseObject(neCountJson, new TypeReference<Map<NeClass, Integer>>() {
                });
            }
        } catch (Exception e) {
            LOG.error("[ne-count-limit] 解析统计数据错误: {}", e);
            return 0;
        }
        // 证书中限制的类型
        Limit limit = Limit.get(neClass);

        if (limit == null) {
            return 0;
        }
        try {
            String prop = limit.name();
            Field field = this.getClass().getDeclaredField(prop);
            if (field == null) {
                return 0;
            }
            Integer count = (Integer) field.get(this);
            count = count == null ? 0 : count;

            int usedNum = 0;

            for (NeClass itm : limit.neClass()) {
                Integer n = ct.get(itm);
                if (n != null && n.compareTo(0) > 0) {
                    usedNum += n;
                }
            }
            return count - usedNum;
        } catch (Exception e) {
            LOG.error("[ne-count-limit]error :{} ", e);
        }
        return 0;
    }

    /**
     * 获取授权点数、中文名称及所包含的neClass
     */
    public JSONArray usedSum(String neCountJson) {
        JSONArray result = new JSONArray();
        // 已经使用的资源类型的数量
        Map<NeClass, Integer> ct = Maps.newHashMap();
        if (Strings.isNullOrEmpty(neCountJson)) {
            return null;
        }
        try {
            if (!Strings.isNullOrEmpty(neCountJson)) {
                ct = JSON.parseObject(neCountJson, new TypeReference<Map<NeClass, Integer>>() {
                });
            }
        } catch (Exception e) {
            LOG.error("[ne-count-limit] 解析统计数据错误: {}", e);
            return null;
        }
        for (Limit limit : Limit.values()) {
            JSONObject obj = new JSONObject();
            try {
                String prop = limit.name();
                Field field = this.getClass().getDeclaredField(prop);
                if (field == null) {
                    return null;
                }
                Integer count = (Integer) field.get(this);
                count = count == null ? 0 : count;
                int usedNum = 0;
                for (NeClass itm : limit.neClass()) {
                    Integer n = ct.get(itm);
                    if (n != null && n.compareTo(0) > 0) {
                        usedNum += n;
                    }
                }
                int beginIndex = prop.lastIndexOf("_");
                String baseName = prop.substring(beginIndex + 1);
                // 点数类型的中文名称
                String cnName;
                if ("host".equals(baseName)) {
                    cnName = "虚拟化宿主机";
                } else if ("vm".equals(baseName)) {
                    cnName = "虚拟机";
                } else {
                    cnName = BaseNeClass.valueOf(baseName).getText();
                }
                obj.put("id", prop);
                obj.put("used", usedNum);
                obj.put("total", count);
                obj.put("name", cnName);
                result.add(obj);
            } catch (Exception e) {
                LOG.error("[ne-count-limit]error :{} ", e);
                return null;
            }
        }
        return result;
    }

    public enum Limit {
                       limit_network("网络设备",Lists.newArrayList(BaseNeClass.network, BaseNeClass.loadBalancing),
                           Lists.newArrayList()),
                       limit_server("服务器",Lists.newArrayList(BaseNeClass.host, BaseNeClass.server),
                           Lists.newArrayList()),
                       limit_database("数据库",Lists.newArrayList(BaseNeClass.database),Lists.newArrayList()),
                       limit_rac("数据库集群",Lists.newArrayList(BaseNeClass.rac),Lists.newArrayList()),
                       limit_storage("存储设备",Lists.newArrayList(BaseNeClass.storage),Lists.newArrayList()),
                       limit_middleware("中间件",Lists.newArrayList(BaseNeClass.middleware),Lists.newArrayList()),
                       // 其他设备
                       limit_other("其他设备",Lists.newArrayList(BaseNeClass.other, BaseNeClass.unknow),
                           Lists.newArrayList()),
                       // 应用
                       limit_app("应用",Lists.newArrayList(BaseNeClass.app),Lists.newArrayList()),
                       limit_virtualization_host("虚拟机",Lists.newArrayList(),Lists.newArrayList(
                       // 控制虚拟机点数
                       )),
                       limit_virtualization_vm("宿主机",Lists.newArrayList(
                       // BaseNeClass.virtualization
                       ),Lists.newArrayList(NeClass.vmware, NeClass.xen, NeClass.kvm, NeClass.esxi, NeClass.cas,
                           NeClass.uxcloud)),
                       limit_cloud("云平台",Lists.newArrayList(BaseNeClass.cloud),Lists.newArrayList()),
                       limit_backup("备份系统",Lists.newArrayList(BaseNeClass.backup),Lists.newArrayList()),
                       limit_video("视频监控",Lists.newArrayList(BaseNeClass.video),Lists.newArrayList());

        String desc;

        private List<NeClass> nes;

        private List<BaseNeClass> bases;

        Limit(String desc, List<BaseNeClass> bases, List<NeClass> nes) {
            this.desc = desc;
            this.bases = bases;
            this.nes = nes;
        }

        public Set<NeClass> neClass() {
            Set<NeClass> sets = Sets.newHashSet();
            sets.addAll(this.nes);
            this.bases.forEach(b -> sets.addAll(b.getNeClass()));
            return sets;
        }

        public static Limit get(NeClass neClass) {
            for (Limit limit : Limit.values()) {
                if (limit.neClass().contains(neClass)) {
                    return limit;
                }
            }
            return null;
        }

        public String desc() {
            return this.desc;
        }

        /**
         * 返回系统控制的对应的neclass
         *
         * @return
         */
        public static Map<String, Map<String, Object>> mapNeClass() {
            Map<String, Map<String, Object>> result = Maps.newHashMap();
            for (Limit limit : Limit.values()) {
                Map<String, Object> property = Maps.newHashMap();
                property.put("name", limit.desc());
                property.put("key", limit.name());
                property.put("nes", limit.neClass());
                result.put(limit.name(), property);
            }
            return result;
        }
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }
}
